-module(test1_game_sess).
-behaviour(gen_server).

%% API
-export([start_link/0, human_move/3]).

%% gen_server callbacks
-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]).

-define(SERVER, ?MODULE).

-define(SIZE, 15).
-define(CENTER, 8).

-record(state, {known_multi_rules,field,next_move}).

%%%===================================================================
%%% API
%%%===================================================================

start_link() ->
    gen_server:start_link(?MODULE, [], []).

human_move(Pid, X,Y) ->
    try
      gen_server:call(Pid, {human_move,X,Y})
    catch
      Type:Reason ->
        %ErrText = lists:flatten(io_lib:format("Catch: ~p ~p",[Type,Reason])),
        io:format("Catch: ~p ~p~n",[Type,Reason]),
        [{error,true}]
    end.

%%% gen_server callbacks:

init([]) -> {ok, []}.

handle_call(init_field, _From, _State) ->
    %io:format("game_sess call~n"),
    Ans = [{coord_min,1},{coord_max,?SIZE},{xc, ?CENTER},{yc, ?CENTER}],
    State = #state{
        known_multi_rules=test1_game:known_multi_rules(), % calculate the rules once only
        field=test1_game:field_new(),
        next_move={?CENTER, ?CENTER}},
    {reply,Ans,State};

handle_call({human_move, X, Y}, _From, #state{field=Field, next_move=NMove} = State) ->
    F = test1_game:field_move2(Field, {x,NMove}),
    case test1_game:field_get(F, X, Y) of
        free ->
            FNew = test1_game:field_move2(Field, {x,NMove,o,{X,Y}}),
            case test_field_win(FNew,o) of
                true ->
                    Ans = [{human_win, true},{human_xc,X},{human_yc,Y}],
                    {stop,normal,Ans,[]};
                false ->
                    MyMove = {MyX,MyY} = choose_move(State#state.known_multi_rules, FNew),
                    Ans = [{xc, MyX},{yc, MyY},{human_xc,X},{human_yc,Y}],

                    FFuture = test1_game:field_move2(FNew, {x,MyMove}),
                    case test_field_win(FFuture,x) of
                        true ->
                            {stop,normal,[{comp_win,true}|Ans],[]};
                        false ->
                            {reply,Ans,State#state{field=FNew, next_move=MyMove}}
                    end
            end;
        _ ->
            {reply,[{cell_not_free,true}],State}
    end.


handle_cast(Msg, State) ->
    io:format("Unexpected cast: ~p~n",[Msg]),
    {noreply,State}.

handle_info(Msg, State) ->
    io:format("Unexpected cast: ~p~n",[Msg]),
    {noreply,State}.

terminate(_Cause, _State) -> ok.
code_change(_OldVsn, State, _Extra) -> {ok, State}.

%%% private funs:

test_field_win(Field,Mark) ->
    case test1_game:field_win(Field,Mark) of
        true ->
            io:format("Finished game ~p~n",[Field]),
            io:format("Finished game ~w~n",[ game_to_moves(lists:reverse(Field)) ]),
            true;
        false -> false
    end.

game_to_moves( [{x,Xx,Yx}, {o,Xo,Yo} | More ] ) -> [{x,Xx,Yx,o,Xo,Yo} | game_to_moves(More) ];
game_to_moves( [] ) -> [];
game_to_moves( [{x,Xx,Yx}] ) -> [{x,Xx,Yx}].


choose_move(KnownMultiRules, Field) ->
    %{2,random:uniform(?SIZE)}.
    test1_game:simple_move_choose(KnownMultiRules, Field,x).